<?php

namespace App\Services;

use App\Models\Setting;
use App\Repositories\SettingRepository;
use Illuminate\Support\Facades\Cache;

class SettingService
{

    /**
     * 配置类型：字符
     */
    const TYPE_STRING = 'string';

    /**
     * 配置类型：图片
     */
    const TYPE_IMAGE = 'image';

    /**
     * 配置类型：单选
     */
    const TYPE_RADIO = 'radio';

    /**
     * 配置类型：文本
     */
    const TYPE_TEXT = 'text';

    /**
     * 配置类型：数字
     */
    const TYPE_NUMBER = 'number';

    /**
     * 配置类型：列表
     */
    const TYPE_LIST = 'list';

    /**
     * 配置类型名称
     *
     * @var array
     */
    static protected $types = [
        self::TYPE_STRING => '字符',
        self::TYPE_NUMBER => '数字',
        self::TYPE_RADIO => '单选',
        self::TYPE_IMAGE => '图片',
        self::TYPE_TEXT => '文本',
        self::TYPE_LIST => '列表',
    ];

    /**
     * @var SettingRepository
     */
    private $repository;

    /**
     * SettingService constructor.
     * @param SettingRepository $repository
     */
    public function __construct(SettingRepository $repository)
    {
        $this->repository = $repository;
    }

    /**
     * 创建配置
     *
     * @param array $attributes
     * @return $this|\Illuminate\Database\Eloquent\Model
     */
    public function create($attributes)
    {
        $setting = $this->repository->create($attributes);
        $this->cache();
        return $setting;
    }

    /**
     * 修改配置
     *
     * @param Setting $setting
     * @param $attributes
     * @return bool
     */
    public function update(Setting $setting, $attributes)
    {
        $result = $this->repository->update($attributes,$setting);
        $this->cache();
        return $result;
    }

    /**
     * 删除配置
     *
     * @param Setting $setting
     * @return bool|null
     * @throws \Exception
     */
    public function destroy(Setting $setting)
    {
        $result = $setting->delete();
        $this->cache();
        return $result;
    }

    /**
     * 缓存配置
     *
     * @return array
     */
    public function cache()
    {
        $settings = $this->getSettingsToArray();
        Cache::forever('settings', $settings);
        return $settings;
    }


    /**
     * 获取所有类型
     *
     * @return array
     */
    public function getTypes()
    {
        return self::$types;
    }


    /**
     * 获取类型名称
     *
     * @param string $type
     * @return mixed|string
     */
    public static function getTypeName($type)
    {
        return key_exists($type, self::$types) ? self::$types[$type] : '';
    }

    /**
     * 验证类型是否存在
     *
     * @param $type
     * @return bool
     */
    public static function validateType($type)
    {
        return key_exists($type, self::$types);
    }

    /**
     * 获取配置分组
     *
     * @return array
     */
    public function getGroups()
    {
        return config('setting.setting_groups') ?: (config('app.setting_groups') ?: []);
    }

    /**
     * 批量保存配置
     *
     * @param array $attributes
     * @return bool
     */
    public function setting(array $attributes)
    {
        if (empty($attributes)) {
            return true;
        }
        $settings = $this->all();
        $settings->map(function ($setting) use ($attributes) {
            if (!key_exists($setting->name, $attributes)) {
                return;
            }
            switch ($setting->type) {
                case self::TYPE_IMAGE:
                    $setting->update(['value' => attachment_in($attributes[$setting->name])]);
                    break;
                case self::TYPE_NUMBER:
                    if (is_numeric($attributes[$setting->name])) {
                        $setting->update(['value' => $attributes[$setting->name]]);
                    }
                    break;
                case self::TYPE_RADIO:
                    $addon_options = self::parseOptions($setting->addon_options);
                    if (isset($addon_options[$attributes[$setting->name]])) {
                        $setting->update(['value' => $attributes[$setting->name]]);
                    }
                    break;
                case self::TYPE_TEXT:
                case self::TYPE_LIST:
                case self::TYPE_STRING:
                default:
                    $setting->update(['value' => $attributes[$setting->name]]);
            }
        });
        $this->cache();
        return true;
    }

    /**
     * 解析配置选项
     *
     * @param string $options_string
     * @return array|false|string[]
     */
    public static function parseOptions($options_string = '')
    {
        if (trim($options_string) == '') {
            return [];
        }
        $lines = preg_split('/[;\r\n]+/', trim($options_string, ";\r\n"));
        $options = [];
        if (strpos($options_string, ':')) {
            foreach ($lines as $line) {
                list($k, $v) = explode(':', $line, 2);
                $options[$k] = $v;
            }
        } else {
            $options = $lines;
        }
        return $options;
    }

    /**
     * 解析配置值
     *
     * @param $value
     * @param $type
     * @return array|false|mixed|string|string[]
     */
    public static function parseValue($value, $type)
    {
        switch ($type) {
            case self::TYPE_IMAGE:
                return attachment_out($value);
            case self::TYPE_LIST:
                return self::parseOptions($value);
        }
        return $value;
    }

    /**
     * 获取指定配置项
     *
     * @param int $id
     * @return mixed
     */
    public function getById($id)
    {
        return $this->repository->getById($id);
    }

    /**
     * 根据名称获取配置名
     *
     * @param string $name
     * @return mixed
     */
    public function getByName($name)
    {
        return $this->repository->getByName($name);
    }

    /**
     * 获取指定分组的所有配置项
     *
     * @param int $group
     * @return \Illuminate\Database\Eloquent\Collection|static[]
     */
    public function getByGroup($group)
    {
        return $this->repository->getByGroup($group);
    }

    /**
     * 获取配置分页列表
     *
     * @param array $condition
     * @param int $per_page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function paginate($condition = [], $per_page = 20)
    {
        return $this->repository->paginate($condition, $per_page);
    }

    /**
     * 获取所有配置项
     *
     * @return mixed
     */
    public function all()
    {
        return $this->repository->all();
    }

    /**
     * 从缓存中获取所有配置
     *
     * @return array
     */
    public function getSettingsFromCache()
    {
        return Cache::rememberForever('settings', function () {
            return $this->getSettingsToArray();
        });
    }


    /**
     * 获取配置数组
     *
     * 解析过后的配置数组
     *
     * @return array
     */
    private function getSettingsToArray()
    {
        $settings = [];
        $this->all()->map(function ($setting) use (&$settings) {
            $settings[$setting->name] = self::parseValue($setting->value, $setting->type);
        });
        return $settings;
    }
}
